Synchronized原理(轻量级锁篇)

您所在的位置:网站首页 synchronized 重入怎么实现 Synchronized原理(轻量级锁篇)

Synchronized原理(轻量级锁篇)

2024-07-17 11:00| 来源: 网络整理| 查看: 265

Synchronized原理(轻量级锁篇) 简述 介绍

轻量级锁是JDK1.6之中加入的新型锁机制,它名字中的“轻量级”是相对于使用操作系统互斥量来实现的传统锁而言的,因此传统的锁机制就称为“重量级”锁。首先需要强调一点的是,轻量级锁并不是用来代替重量级锁的,它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。

轻量级锁能够提升程序性能的依据是“对绝大部分的锁,在整个同步周期内都不存在竞争”,注意这是经验数据。需要了解的是,轻量级锁所适应的场景是线程交替执行同步块的场合,如果存在同一时间访问同一锁的场合,就会导致轻量级锁膨胀为重量级锁。

引入轻量级锁的目的

JVM的开发者发现在很多情况下,在Java程序运行时,同步块中的代码都是不存在竞争的,不同的线程交替的执行同步块中的代码。这种情况下,用重量级锁是没必要的。因此JVM引入了轻量级锁的概念。

优点

竞争的线程不会阻塞,使用自选,提高程序响应速度。

缺点

如果一直不能获取到锁,长时间的自旋会造成CPU消耗。

适用场景

适用于少量线程竞争锁对象,且线程持有锁的时间不长,追求响应速度的场景。

工作流程

在这里插入图片描述

入口

轻量级锁的进入方式有三种

对象处于未锁定不可偏状态

在这里插入图片描述

此状态下对象不能进入偏向锁模式,当有线程尝试获取锁时,会通过轻量级锁的方式获取锁。

对象锁已经偏向于线程(不考虑重偏向场景)

在这里插入图片描述

当锁已经偏向于线程,且线程处于锁定状态或处于未锁定但不允许重偏向的情况下,其它的线程尝试获取锁时,会触发偏向锁撤销,然后升级为轻量级或重量级锁定。

对象被轻量级锁定

在这里插入图片描述

当对象已经被轻量级锁定的时候,会判断是否是锁重入,如果是重入的话,会记录一条Displaced Mark Word为空的Lock Record。如果不是重入,会膨胀为重量级锁。需要注意的是,即使膨胀为重量级锁,没有获取到锁的线程也不会马上阻塞,而是通过适应性自旋尝试获取锁,当自旋次数达到临界值后,才会阻塞未获取到的线程。JVM认为获取到锁的线程大概率会很快的释放锁,这样做是为了尽可能的避免用户态到内核态的切换。

加锁过程

code 1 :判断对象是否是无锁状态(低三位 = 001),如果是,执行code 2,如果不是,执行code 4。

code 2:在栈中建立一个Lock Record,将无锁状态的Mark Word拷贝到锁记录的Displaced Mark Word中,将owner指向当前对象。

code 3:尝试通过CAS 将锁对象的 Mark Word 更新为指向Lock Record的指针,如果更新成功,该线程获取到轻量级锁,并且需要把对象头的Mark Word的低两位改成10(注意这里修改的是对象头的Mark Word,Lock Record中记录的还是无锁状态的Mark Word);如果更新失败,执行code 4。

code 4:对象是轻量级锁定状态,判断对象头的 Mark Word是否指向当前线程的栈帧。如果是,则这次为锁重入,将刚刚建立的Lock Record中的Displaced Mark Word设置为null,记录重入,该线程重入轻量级锁。如果不是,执行code 5。

code 5:线程获取轻量级锁失败,锁膨胀为重量级锁,对象头的Mark Word改为指向重量级锁monitor的指针。获取失败的线程不会立即阻塞,先适应性自旋,尝试获取锁。到达临界值后,阻塞该线程,直到被唤醒。

适应性自旋

自适应意味着自旋的时间(次数)不再固定,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也是很有可能再次成功,进而它将允许自旋等待持续相对更长的时间。如果对于某个锁,自旋很少成功获得过,那在以后尝试获取这个锁时将可能省略掉自旋过程,直接阻塞线程,避免浪费处理器资源。

图解 无锁状态获取锁

线程执行到同步块时,同步对象处于无锁状态,锁标志位为01,偏向标志位为0,偏向锁被禁用,对象处于无锁态。

在这里插入图片描述

在加锁前,虚拟机需要在当前线程的栈帧中建立锁记录(Lock Record)的空间。Lock Record 中包含一个 _displaced_header 属性,用于存储锁对象的 Mark Word 的拷贝。

在这里插入图片描述

将锁对象的 Mark Word 复制到锁记录中,这个复制过来的记录叫做 Displaced Mark Word。具体来讲,是将 mark word 放到锁记录的 _displaced_header 属性中,将Owner指向当前对象。

在这里插入图片描述

虚拟机使用 CAS 操作尝试将锁对象的 Mark Word 更新为指向锁记录的指针。如果更新成功,这个线程就获得了该对象的锁。

在这里插入图片描述

更新成功后,需要修改原对象头Mark Word中的锁状态标志位为00,目的是告诉其它线程此对象已经被轻量级锁定。

在这里插入图片描述

重入锁

当对象处于加锁状态时,会去检验Mark Word是否指向当前线程的栈帧,如果是则将刚刚建立的Lock Record中的Displaced Mark Word设置为null,记录线程重入锁。

在这里插入图片描述

非重入锁

如果指向的不是当前线程的栈帧则会触发锁膨胀,膨胀为重量级锁。

在这里插入图片描述 Thread2把锁膨胀为重量级锁,Thread1获取到重量级锁,Thread2适应性自旋尝试获取锁,到达临界值后进入等待队列阻塞。 在这里插入图片描述 这里注意执行锁膨胀的线程为Thread2,而非原轻量级锁的持有者Thread1。

解锁过程

轻量级锁加锁时有锁重入的可能,同样的,在解锁时也需要判断是否是锁重入解锁。

code 1 :检索当前线程栈中的锁记录空间,从低位往高位找到第一条和此对象有关的Lock Record。加锁时,如果是锁重入,会将 Displaced Mark Word 设置为 null,相应的,在解锁时需要判断Displaced Mark Word是否为 null,如果是,则说明是锁重入解锁,移除onwer的指向,不做替换操作;如果不是,执行code 2。

code 2:通过CAS把当前线程栈帧Lock Record中的Displaced Mark Word替换到对象头的Mark Word中去,如果替换成功,则轻量级解锁成功;如果替换失败,则说明发生了锁膨胀,对象现在是重量级锁定状态,执行code 3。

code 3:执行重量级锁释放流程(详细过程下篇文章会将),释放重量级锁,同时唤醒被阻塞的线程去获取锁。

图解 非重入释放锁

解锁的思路是使用 CAS 操作把当前线程的栈帧中的 Displaced Mark Word 替换回锁对象中去,如果替换成功,则解锁成功。

在这里插入图片描述

CAS成功

在这里插入图片描述

CAS失败

在这里插入图片描述

轻量级锁未释放前被其它线程尝试获取,此时Mark Word指针已经被替换为指向Monitor,释放锁时CAS会失败,此时需要走重量级解锁流程。

PS:关于重量级解锁流程下篇文章会补充。

重入释放锁

加锁时,如果是锁重入,会将 Displaced Mark Word 设置为 null。相对应地,解锁时,如果判断 Displaced Mark Word 为 null 则说明是锁重入,不做替换操作。

在这里插入图片描述

归纳总结 轻量级锁的适用场景

少量的线程竞争锁,且所有者线程占用锁的事件补偿,追求响应速度的场景。

什么时候会升级为轻量级锁

当对象的偏向模式被关闭、对象处于已偏向已锁定、已偏向未锁定但不支持重偏向的场景下,就会升级为轻量级锁。

什么时候会升级为重量级锁

当竞争产生时就会升级为重量级锁,比如,两个线程同时获取锁,成功的线程会获取到轻量级锁,失败的线程会执行锁膨胀,升级为重量级锁。

轻量级锁怎样实现锁重入

当轻量级锁已经被线程持有,且对象头的Mark Word指向的是当前线程的栈帧时,会把本条Lock Record的Displaced Mark Word 设置为 null,实现锁重入。当重入解锁时,只需要修改所有者onwer的指向。

轻量级锁是否会自旋

轻量级锁流程不会自旋,自旋发生在产生竞争后,获取失败的线程将锁膨胀为重量级锁。失败的线程不会立刻阻塞,而是先尝试适应性自旋,等待所有者释放锁,当到达临界值后再阻塞。

End

轻量级锁可以看作是偏向锁重偏向的升级版,加入了有锁到无锁的状态转换,即使当竞争产生时升级到重量级锁,也不会马上阻塞线程,而是通过适应性自旋来决定是否阻塞,提高了性能。轻量级锁相较于偏向锁来说,简单一些,下一篇会着重介绍重量级锁,以及自旋的线程是怎样进入重量级锁的等待队列的。

参考文献

jdk源码剖析二: 对象内存布局、synchronized终极原理 - 只会一点java - 博客园 (cnblogs.com)

死磕Synchronized底层实现–轻量级锁 · Issue #14 · farmerjohngit/myblog (github.com)



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3